package com.alogic.xscript.plugins;

import java.util.HashMap;
import java.util.Map;

import com.alogic.reload.ReloadFactory;
import com.alogic.reload.Reloader;
import com.anysoft.util.*;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Element;

import com.alogic.load.Loadable;
import com.alogic.load.Store.HashStore;
import com.alogic.xscript.ExecuteWatcher;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.doc.XsObject;
import com.alogic.xscript.doc.json.JsonObject;

/**
 * 文档缓存
 * 
 * @author yyduan
 * @since 1.6.12.3 [20181013 duanyy]
 * 
 * @version 1.6.12.6 [20181105 duanyy] <br>
 * - 增加refresh参数 <br>
 *
 * @version  1.6.13.5 [20200605 duanyy] <br>
 * - 集成reload框架
 */
public class DocCache extends Segment {
	protected String $tag = "data";
	protected String $id = "";
	protected String $domain = "default";
	protected DocStore store = null;
	protected String $refresh = "false";
	protected boolean autoReload = true;
	
	public DocCache(String tag, Logiclet p) {
		super(tag, p);
	}

	@Override
	public void configure(Properties p){
		super.configure(p);
		$id = PropertiesConstants.getRaw(p,"id","");
		$tag = PropertiesConstants.getRaw(p,"tag", $tag);
		$refresh = PropertiesConstants.getRaw(p,"refresh", $refresh);
		$domain = PropertiesConstants.getRaw(p,"domain","default");
		autoReload = PropertiesConstants.getBoolean(p,"autoReload",true);
		store = new DocStore();
		store.configure(p);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	protected void onExecute(XsObject root,XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
		if (current instanceof JsonObject){
			String tag = PropertiesConstants.transform(ctx, $tag, "");
			String id = PropertiesConstants.transform(ctx, $id, "");
			if (StringUtils.isNotEmpty(tag) && StringUtils.isNotEmpty(id)){
				boolean refresh = PropertiesConstants.transform(ctx,$refresh,false);
				CachedDoc doc = refresh ? null:store.load(id, true);
				if (doc != null && autoReload){
					Reloader reloader = ReloadFactory.getReloader();
					if (reloader != null){
						if (reloader.reload(id,PropertiesConstants.transform(ctx,$domain,"default"),doc)){
							doc = null;
							store.del(id);
						}
					}
				}
				if (doc == null){
					synchronized(this){
						doc = refresh ? null:store.load(id, true);
						if (doc == null){
							doc = new CachedDoc(id,new HashMap<String,Object>());
							JsonObject newCurrent = new JsonObject(tag,(Map<String,Object>)doc.getData());
							super.onExecute(root, newCurrent, ctx, watcher);
							store.save(id, doc, true);
						}
					}
				}
				Map<String,Object> jsonCurrent = (Map<String, Object>) current.getContent();					
				jsonCurrent.put(tag, doc.getData());
			}
		}else{
			throw new BaseException("core.e1000",
					String.format("Tag %s does not support protocol %s",
							getXmlTag(),root.getClass().getName()));	
		}
	}	
	
	/**
	 * Store
	 * @author yyduan
	 *
	 */
	public static class DocStore extends HashStore<CachedDoc>{

		@Override
		public CachedDoc newObject(String id) {
			return new CachedDoc(id,null);
		}
		
	}
	
	/**
	 * 文档
	 * @author yyduan
	 *
	 */
	public static class CachedDoc extends Loadable.Abstract{
		protected String id;
		protected Object data;
		
		public CachedDoc(String id,Object data){
			this.id = id;
			this.data = data;
		}
		
		public Object getData(){
			return this.data;
		}
		
		public void setData(Object data){
			this.data = data;
		}
		
		@Override
		public String getId() {
			return id;
		}

		@Override
		public void report(Element xml) {
			if (xml != null){
				XmlTools.setString(xml,"module",getClass().getName());
			}
		}

		@Override
		public void report(Map<String, Object> json) {
			if (json != null){
				JsonTools.setString(json,"module",getClass().getName());
			}
		}
	}
}
